var net = require('net')
var skynet = require("./seri")

var session_cb = {}
var session_ud = {}

var node_address = {}
var node_clients = {}

var session_counter = 1

function gen_session() {
	return session_counter++
}

function unpack_string(buf, offset) {
	var namelen = buf[offset]
	var name = buf.toString('utf8', offset+1, offset+1+namelen)

	offset += (1+namelen)

	var session = buf.readUInt32LE(offset)

	offset += 4
	var content = skynet.unpack(buf.slice(offset))

	return {session, name, content}
}

function unpack_number(buf, offset) {
	var session = buf.readUInt32BE(offset)

	offset += 4
	var content = skynet.unpack(buf.slice(offset))

	return {session, content}
}

/*
	字节数		内容
	2: 			sz+6+namelen
	1: 			flag(0x81、....)
	1: 			namelen
	namelen: 	name
	4: 			session
	sz: 		msg
 */
function unpackrequest(data) {
	var sz = data.readUInt16BE(0)	// js 可以不用 sz 来解包
	var flag = data[2]
	if (flag == 0x80) {
		return unpack_string(data, 3)
	}
}

function printBuffer(buffer) {
	var str = ""
	for (var i = 0; i < buffer.length; i++) {
		str += buffer.toString("hex", i, i+1) + " "
	}

	return str
}

function start_tcp_server(ip, port) {
	console.log("start tcp server ...", ip, port)

	var server = net.createServer((session) => {

		session.on("data", (data) => {
			// console.log("client data:", printBuffer(data))
			if (cluster._dispatch) {
				var tb = unpackrequest(data)
				if (tb.session > 0 && !session_ud[tb.session]) {
					session_ud[tb.session] = session
				}

				try {
					cluster._dispatch(tb.name, tb.session, tb.content)
				} catch (error) {
					response(tb.session, false, error + "")
				}
			}
		})

		session.on("error", (error) => {
			console.log("client socket error:", error)
			session.end()
		})
	})

	server.on("error", (err) => {
		console.log("server listen error...", err)
	})

	server.on("close", () => {
		console.log("server listen close...")
	})

	server.listen({
		host: ip,
		port: port,
		exclusive: true,
	})
}

function fill_header(buf, offset, size) {
	return buf.writeUInt16LE(size, offset)
}

function packresponse(session, ok, msg) {
	var msgbuf = skynet.pack(msg)
	var sendbuf = Buffer.allocUnsafe(msgbuf.length + 7)

	var offset = sendbuf.writeUInt16BE(5 + msgbuf.length, 0)
	offset = sendbuf.writeUInt32LE(session, offset) 		// session
	offset = sendbuf.writeUInt8(ok, offset)					// ok
	sendbuf.fill(msgbuf, offset, offset + msgbuf.length)	// msg

	return sendbuf
}

function response(ud, ok, msg) {
	if (!skynet.checktype(msg, "object")) {
		console.log("cluster response msg must be a object", msg)
		return
	}

	if (ud <= 0) {
		console.log("cluster response session must be greater than zero", ud)
		return
	}

	var session = session_ud[ud]
	session_ud[ud] = null

	session.write(packresponse(ud, ok, msg))
}

/*
	字节数		内容
	2: 			sz+6+namelen
	1: 			flag(0x80、 0x81、....)
	1: 			namelen
	namelen: 	name
	4: 			session
	sz: 		msg
 */
function packrequest(address, data, session) {
	var msgbuf = skynet.pack(data)
	var total = msgbuf.length + 8 + address.length
	var buf = Buffer.allocUnsafe(total)

	var offset = buf.writeUInt16BE(total - 2, 0)
	offset = buf.writeUInt8(0x80, offset)
	offset = buf.writeUInt8(address.length, offset)
	offset += buf.write(address, offset, address.length)
	offset = buf.writeUInt32LE(session, offset)

	buf.fill(msgbuf, offset, offset + msgbuf.length)

	return buf
}

function unpackresponse(buf) {
	var offset = 2
	var session = buf.readUInt32LE(offset) //unpack_uint32(buf, offset)
	offset += 4

	var ok = buf.readUInt8(offset)
	offset += 1
	
	var content = skynet.unpack(buf.slice(offset))

	return {session, content}
}

function call(node, address, data, callback) {
	var client = node_clients[node]
	var session = 0

	if (callback) {
		session = gen_session()
		session_cb[session] = callback
	}

	if (!client) {
		var c = node_address[node]
		if (c) {
			client = net.createConnection({ port: c.port, host: c.host })
			node_clients[node] = client
		}

		client.on('data', (msg)=> {
			var t = unpackresponse(msg) || {}
			if (t && session_cb[t.session]) {
				var cb = session_cb[t.session]
				session_cb[t.session] = null
				cb(t.session, t.content)
			}
		})
	}

	if (!client) {
		console.log("Connect to" + node +" failed")
		return
	}

	client.write(packrequest(address, data, session))
}

function send(node, address, data) {
	call(node, address, data)
}

function reload(nodes) {
	for (var i in nodes) {
		var node = nodes[i]
		var t = node.split(":")
		if (t) {
			node_address[i] = {host: t[0], port: t[1]}
		}
	}
}

// start_tcp_server("0.0.0.0", 8822)
/*
	cluster.call(session 不为 0): (A打包消息)lpackrequest --> (B处理消息)lunpackrequest --> (B返回结果)lpackresponse --> （A得到B的结果)lunpackresponse
	cluster.send(session   为 0): (A打包消息)lpackrequest --> (B处理消息)lunpackrequest
*/

var cluster = {
	listen: start_tcp_server,
	ret: response,
	reload: reload,
	call: call,
	send: send,

	dispatch: function(f) {
		this._dispatch = f
	},

}

module.exports = cluster


